/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mdnsapp;

import java.util.Enumeration;
import java.util.Hashtable;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.jmdns.ServiceTypeListener;
import javax.jmdns.impl.JmDNSImpl;
import mdnsapp.MDNSView.OverlayData;

/**
 *
 * @author Qaisar
 */
public class MDNSModule implements ServiceListener, ServiceTypeListener {

    static JmDNSImpl dns;
    boolean supernode = true;
    static String superNodeServiceType = "_supernode._tcp.local.";
    static String clientNodeServiceType = "_clientnode._tcp.local.";
    static String bootstrapNodeServiceType = "_bootstrapnode._tcp.local.";
    MDNSView appView;

    public MDNSModule() {
        System.out.println("Trying to get MainView..");
        appView = MDNSApp.getApplication().mdnsView;

    }

    public void booting(String peerType) {
        if (supernode) //supernode = true means its supernode..
        {
            try {
                String serviceType = peerType;
                String serviceName = "Scope:" + dns.getHostName() + peerType;
                int port = 3630;
                int weight = 0;
                int prio = 0;
                Hashtable txt = new Hashtable();
                txt.put("supernodename", dns.getHostName());
                txt.put("overlayname", "Scope");

                dns.registerService(ServiceInfo.create(serviceType, serviceName, port, weight, prio, txt));

            } catch (Exception ex) {
                System.err.println("Exception registering service = " + ex.getMessage());
            }
        }
    }

    public void registerServiceListerners() {
        String list[] = new String[]{
            "_http._tcp.local.",
            "_ftp._tcp.local.",
            "_tftp._tcp.local.",
            "_ssh._tcp.local.",
            "_smb._tcp.local.",
            "_printer._tcp.local.",
            "_airport._tcp.local.",
            "_afpovertcp._tcp.local.",
            "_ichat._tcp.local.",
            "_eppc._tcp.local.",
            "_presence._tcp.local.",
            superNodeServiceType,
            clientNodeServiceType,
            bootstrapNodeServiceType
        };
        try {
            for (int i = 0; i < list.length; i++) {
                dns.addServiceListener(list[i], this);
                dns.registerServiceType(list[i]);
            }
        } catch (Exception ex) {
            System.err.println("Exception in MDNSView.registerServiceListerners() is " + ex.getMessage());
        }

    }

    public boolean startDNS() {
        try {
            dns = appView.dns = new JmDNSImpl();
            return true;
        } catch (Exception ex) {
            System.err.println("Exception in MDNSView constructor is " + ex.getMessage());
            return false;
        }
    }

    public void serviceAdded(ServiceEvent event) {
        final String name = event.getName();
        final String type = event.getType();
        try {
            final String overlay = name.substring(0, name.indexOf(":"));
            final String serviceName = name.substring(name.indexOf(":") + 1, name.length());
            System.err.println("serviceAdded:Check:Overlayname:" + overlay + ":");
            OverlayData data;
            if (appView.systemData.containsKey(overlay)) {

                data = (OverlayData) appView.systemData.get(overlay);
                System.out.println("value for overlay " + overlay + " in systemData hashtable found with supernodes = " + data.supernode.size() + " services  = " + data.service.size());
            } else {

                data = new OverlayData(overlay);
                System.out.println("value for overlay " + overlay + " not found..");
                appView.systemData.put(overlay, data);
            }
            System.out.println("name = " + serviceName + " Overlayname = " + overlay);

            if (type.equals(bootstrapNodeServiceType)) { // if supernode is added..

                if (!data.supernode.contains(serviceName)) {
                    System.out.println("Adding " + serviceName + " to data.supernode of overlay " + overlay);
                    //data.supernode.add(serviceName);
                    appView.bootStrapNode = serviceName;
                }
                if (!appView.overlayListModel.contains(overlay)) {
                    appView.overlayListModel.addElement(overlay);
                }
                if (overlay.equals(appView.ConnectedOverlay) && !appView.SupernodeListModel.contains(serviceName)) {
                    appView.SupernodeListModel.addElement(serviceName);
                }
            }

            else if (type.equals(superNodeServiceType)) { // if supernode is added..

                if (!data.supernode.contains(serviceName)) {
                    System.out.println("Adding " + serviceName + " to data.supernode of overlay " + overlay);
                    data.supernode.add(serviceName);
                }
                if (!appView.overlayListModel.contains(overlay)) {
                    appView.overlayListModel.addElement(overlay);
                }
                if (overlay.equals(appView.ConnectedOverlay) && !appView.SupernodeListModel.contains(serviceName) && appView.connected) {
                    appView.SupernodeListModel.addElement(serviceName);
                }
            } else if (type.equals(clientNodeServiceType)) { // if clientnode is added..

                if (!data.client.contains(serviceName)) {
                    System.out.println("Adding " + serviceName + " to data.clientnode of overlay " + overlay);
                    data.client.add(serviceName);
                }
                /* if (!overlayListModel.contains(overlay)) {
                overlayListModel.addElement(overlay);
                }*/
                if (overlay.equals(appView.ConnectedOverlay) && !appView.ClientsListModel.contains(serviceName) && appView.connected) {
                    appView.ClientsListModel.addElement(serviceName);
                }
            } else { // if service other than supernode or clientnode is added..
                if (!data.service.contains(serviceName)) {
                    System.out.println("Adding " + serviceName + " to data.service of overlay " + overlay);
                    data.service.put(serviceName, type); // adding service and its type to this overlay..
                }
                if (overlay.equals(appView.ConnectedOverlay) && !appView.OverLayServiceListModel.contains(serviceName) && appView.connected) {
                    appView.OverLayServiceListModel.addElement(serviceName);
                }
            }



        } catch (Exception ex) {
            System.err.println("Service from some other overlay is discovered with name " + name);
        }
    }

    public void serviceRemoved(ServiceEvent event) {
        try {
            appView.ServiceInfoList.remove(event.getInfo());
            final String name = event.getName();
            final String type = event.getType();
            System.out.println("REMOVE: " + name);
            final String overlay = name.substring(0, name.indexOf(":"));
            final String serviceName = name.substring(name.indexOf(":") + 1, name.length());
            OverlayData data;
            if (appView.systemData.containsKey(overlay)) {
                data = (OverlayData) appView.systemData.get(overlay);
            } else {
                System.err.println("Can't find removed service in systemData");
                return;
            }
            if (type.equals(superNodeServiceType)) {
                if (data.supernode.contains(serviceName)) {
                    data.supernode.remove(serviceName);
                }
                if (overlay.equals(appView.ConnectedOverlay) && appView.SupernodeListModel.contains(serviceName)) {
                    appView.SupernodeListModel.removeElement(serviceName);
                }
            } else if (type.equals(clientNodeServiceType)) {
                if (data.client.contains(serviceName)) {
                    data.client.remove(serviceName);
                }
                if (overlay.equals(appView.ConnectedOverlay) && appView.ClientsListModel.contains(serviceName)) {
                    appView.ClientsListModel.removeElement(serviceName);
                }
            } else {
                if (data.service.contains(serviceName)) {
                    System.out.println("Removing " + serviceName + " to data.service of overlay " + overlay);
                    data.service.remove(serviceName); // adding service and its type to this overlay..
                }
                if (overlay.equals(appView.ConnectedOverlay) && appView.OverLayServiceListModel.contains(serviceName)) {
                    appView.OverLayServiceListModel.removeElement(serviceName);
                }
            }

            if (data.client.size() == 0 && data.supernode.size() == 0 && data.service.size() == 0) // checkin if overlay is removed...
            {
                appView.overlayListModel.removeElement(overlay);
                appView.systemData.remove(overlay);
                System.out.println("Overlay " + overlay + " removed...");
            }

        } catch (Exception ex) {
            System.err.println("Some other service not concerning to our system is removed...");
        }
    }

    public void serviceResolved(ServiceEvent event) {
        String name = event.getName();
        String type = event.getType();
        System.err.println("I am in serviceResolved with type = " + type + "and name = " + name);
        ServiceInfo info = event.getInfo();
        if (info == null) {
            System.err.println("info in service " + name + " is null in method serviceResolved..");
            appView.Info.setText("service not found");
        } else {

            StringBuffer buf = new StringBuffer();
            buf.append("Name: " + name);
            buf.append('\n');
            buf.append("Type: " + type);
            buf.append('\n');
            buf.append("Domain: " + info.getServer());
            buf.append('\n');
            buf.append("Address: " + info.getAddress());
            buf.append('\n');
            buf.append("Port: " + info.getPort());
            buf.append('\n');
            for (Enumeration names = info.getPropertyNames(); names.hasMoreElements();) {
                String prop = (String) names.nextElement();
                buf.append(prop);
                buf.append('=');
                buf.append(info.getPropertyString(prop));
                buf.append('\n');
            }
            appView.Info.setText(buf.toString());
            if (type == MDNSModule.superNodeServiceType || type == MDNSModule.bootstrapNodeServiceType) {
                appView.selectedSupernodeInfo = info;
            }

        }
    }

    public void serviceTypeAdded(ServiceEvent event) {
        System.out.println("TYPE: " + event.getType());

    }
}
